#pragma once

#include <iostream>
#include <vector>
#include <pthread.h>

#include "Sem.hpp"
#include "Mutex.hpp"

namespace RingBufferModule
{
    using namespace SemModule;
    // using namespace LockModule;

    // template <typename T>
    // class RingBuffer
    // {
    // public:
    //     RingBuffer(int cap): _ring(cap), _cap(cap), _p_step(0), _c_step(0), _datasem(0), _spacesem(cap)
    //     {
    //         //pthread_mutex_init(&_p_lock, nullptr);
    //         //pthread_mutex_init(&_c_lock, nullptr);
    //     }

    //     void Equeue(const T &in)
    //     {
    //         // 生产者
    //         _spacesem.P();
    //         {
    //             LockGuard lockguard(_p_lock);
    //             _ring[_p_step] = in; // 生产完毕
    //             _p_step++;
    //             _p_step %= _cap;     // 维持唤醒特性
    //         }
    //         _datasem.V();

    //         // // 生产者
    //         // //pthread_mutex_lock(&_p_lock); // 锁要在这里嘛？① 
            
    //         // _spacesem.P();

    //         // pthread_mutex_lock(&_p_lock); // 锁要在这里嘛？②
    //         // _ring[_p_step] = in; // 生产完毕
    //         // _p_step++;
    //         // _p_step %= _cap;     
    //         // _datasem.V();
            
    //         // pthread_mutex_unlock(&_p_lock);
    //     }
    //     void Pop(T *out)
    //     {
    //         // 消费者
    //         _datasem.P();
    //         {
    //             LockGuard lockguard(_c_lock);
    //             *out = _ring[_c_step]; // 预订
    //             _c_step++;
    //             _c_step %= _cap;
    //         }
    //         _spacesem.V();
        
    //         //  // 消费者
    //         // _datasem.P();
    //         // pthread_mutex_lock(&_c_lock);

    //         // *out = _ring[_c_step]; // 预订
    //         // _c_step++;
    //         // _c_step %= _cap;
    //         // _spacesem.V();

    //         // pthread_mutex_unlock(&_c_lock);
    //     }

    //     ~RingBuffer()
    //     {
    //         //pthread_mutex_destroy(&_p_lock);
    //         //pthread_mutex_destroy(&_c_lock);
    //     }

    // private:
    //     std::vector<T> _ring;   // 环， 临界资源
    //     int _cap;               // 总容量
    //     int _p_step;            // 生产者位置
    //     int _c_step;            // 消费位置

    //     Sem _datasem;         // 数据信号量
    //     Sem _spacesem;        // 空间信号量

    //     // pthread_mutex_t _p_lock;
    //     // pthread_mutex_t _c_lock;

    //     Mutex _p_lock;
    //     Mutex _c_lock;

    // };




    // 版本 1 

    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap): _ring(cap), _cap(cap), _p_step(0), _c_step(0), _datasem(0), _spacesem(cap)
        {    
            // 验证缓冲区容量是否有效
            if (cap <= 0)
            {
                std::cout << "Buffer capacity must be greater than zero." <<std::endl;
            }
        }

        // 这里我们为什么没有做判断 ?
        // 原因：信号量，本身就是表示资源数目的，只要成功， 就一定会有, 不需要判断!! -> sem
        // 之前 if 判断那里是把资源当作整体来申请，但是不会去整体使用(局部使用)
        // 而且我们也不知道使用情况，所有需要在内部做判断
        void Equeue(const T &in)
        {
            // 生产者
            _spacesem.P();
            _ring[_p_step] = in; // 生产完毕
            _p_step++;
            _p_step %= _cap;     // 维持唤醒特性
            _datasem.V();
        }
        void Pop(T *out)
        {
            // 消费者
            _datasem.P();
            *out = _ring[_c_step]; // 预订
            _c_step++;
            _c_step %= _cap;
            _spacesem.V();
        }

        ~RingBuffer()
        {
        }
    private:
        std::vector<T> _ring;   // 环， 临界资源
        int _cap;               // 总容量
        int _p_step;            // 生产者位置
        int _c_step;            // 消费位置

        Sem _datasem;         // 数据信号量
        Sem _spacesem;        // 空间信号量
    };
}